package com.chujian.framework.echo;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.chujian.framework.annotation.echo.UseEcho;
import com.chujian.framework.util.Spring;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 回显服务类
 *
 * @author yj
 * @since 2021-12-11
 */
@Slf4j
public class EchoService {

    // 解析器
    private static final IEchoParser echoParser = new EchoParser();
    // 数据服务类缓存
    private static final Map<Class<?>, IEchoDataService<?>> DATA_SERVICE_CACHE = new ConcurrentHashMap<>();

    /**
     * 回显
     *
     * @param result
     * @param useEcho
     */
    public void echo(Object result, UseEcho useEcho) {
        if (null == result) return;

        // # 将数据统一转为list
        List<?> dataList = getListData(result);
        if (CollUtil.isEmpty(dataList)) return;

        // # 类解析
        Class<?> entityClass = dataList.get(0).getClass();
        EchoClassInfo classInfo = echoParser.parseClass(entityClass);
        if (CollUtil.isEmpty(classInfo.getFieldInfos())) return;

        // # 循环字段
        for (EchoFieldInfo fieldInfo : classInfo.getFieldInfos()) {
            // # 获取ID
            List<Serializable> fieldIds = getFieldIds(dataList, fieldInfo.getField());
            if (CollUtil.isEmpty(fieldIds)) continue;

            // # 获取数据服务
            IEchoDataService<?> echoDataService = getEchoDataService(fieldInfo.getDataServiceClass());

            // # 获取呆填充的数据
            Map<Serializable, ?> echoData = echoDataService.getEchoData(fieldIds);

            // # 填充数据/回显数据
            doEcho(dataList, echoData, fieldInfo);
        }
    }

    /**
     * 将数据统一转为list
     *
     * @param result
     * @return
     */
    private List<?> getListData(Object result) {
        // Ipage
        if (result instanceof IPage) {
            return ((IPage<?>) result).getRecords();
        }
        // list
        if (result instanceof List) {
            return ((List<?>) result);
        }
        // 单值
        return ListUtil.toList(result);
    }

    /**
     * 获取 EchoDataService
     *
     * @param dataServiceClass
     * @return
     */
    private IEchoDataService<?> getEchoDataService(Class<?> dataServiceClass) {
        if (DATA_SERVICE_CACHE.containsKey(dataServiceClass)) {
            return DATA_SERVICE_CACHE.get(dataServiceClass);
        }
        synchronized (DATA_SERVICE_CACHE) {
            if (DATA_SERVICE_CACHE.containsKey(dataServiceClass)) {
                return DATA_SERVICE_CACHE.get(dataServiceClass);
            }
            IEchoDataService<?> service = ((IEchoDataService<?>) Spring.getBean(dataServiceClass));
            DATA_SERVICE_CACHE.put(dataServiceClass, service);
            return service;
        }
    }

    /**
     * 获取Field的ids
     *
     * @param dataList
     * @param field
     * @return
     */
    private List<Serializable> getFieldIds(List<?> dataList, Field field) {
        List<Serializable> fieldIds = dataList.stream()
                // 获取ID
                .map(item -> ((Serializable) ReflectUtil.getFieldValue(item, field)))
                // 非空
                .filter(Objects::nonNull)
                // 去重
                .distinct()
                .collect(Collectors.toList());
        return fieldIds;
    }

    /**
     * 回显
     *
     * @param dataList
     * @param echoData
     * @param fieldInfo
     */
    private void doEcho(List<?> dataList, Map<Serializable, ?> echoData, EchoFieldInfo fieldInfo) {
        Field field = fieldInfo.getField();
        String fieldName = field.getName();
        Field targetField = fieldInfo.getTargetField();

        Serializable id;
        Object value;

        // ## 1. 回显到目标字段
        if (null != targetField) {
            for (Object obj : dataList) {
                id = (Serializable) ReflectUtil.getFieldValue(obj, field);
                value = echoData.get(id);
                ReflectUtil.setFieldValue(obj, targetField, value);
            }

        }
        // ## 2. 回显到通用的map中
        else {
            for (Object obj : dataList) {
                if (obj instanceof IEchoModel) {
                    id = (Serializable) ReflectUtil.getFieldValue(obj, field);
                    value = echoData.get(id);
                    ((IEchoModel) obj).getEchoMap().put(fieldName, value);
                }
            }

        }
    }
}
